<?php
/**
 +------------------------------------------------------------------------------
 * 库存检查
 +------------------------------------------------------------------------------
 * @copyright   2011 友拓软件友拓通
 * @category   	基本信息
 * @package  	Model 
 +------------------------------------------------------------------------------
 */
class CheckStoragePublicModel extends Model {
	protected $tableName = 'storage';
	protected $params 		= array();
	protected $checkData		= array();
	protected $storage_attr 	= array();
	protected $module_name = '';
	protected $reduce = false;
	
	/**
	 * 库存检查公共接口
	 *
	 * @param  参数 $params
	 * @param  方法名称，默认取模块名称，首字母转小写
	 */
	public function run($params,$module_name=null){
		$this->module_name = ucwords_first($this->_module);
		$this->params = $params;
		$this->setSpec();
		
		// 销售关联配货，退货新增时验证可销售库存，其它验证实际库存
		if (($this->_module=='SaleOrder') || ($this->_module=='ReturnSaleOrder' && $this->_action=='insert')){
			if (C('sale.relation_sale_follow_up')==1) {
				$this->tableName = 'saleStorage';
			}
			$this->reduce = true;
		}
		// 合并修改后的数据（页面传递）的同规格数据（以库存规格为标准合并）
		// 设置数据中的下标名称
		$detail_key = ($this->_module=='ReturnSaleOrder' && $this->_action=='insert') ? 'sale' : 'detail';
		$post_data = $this->postMerge($detail_key);
//		 检查是否指定出库
//		$this->checkFiFo(intval($this->params['id']),$post_data);
		// 获取修改前的数据（取DB数据）
		$db_data = $this->dbMerge();
		// 计算本次操作最终修改量
		$this->setCheckData($post_data,$db_data);
		// 验证库存数量是否足够
		$this->execCheckStorage();
	}
	
	/**
	 * 根据配置信息获取库存更新属性
	 *
	 */
	protected function setSpec(){
		static $storage_attr;
		if($storage_attr) {
			return ;
		}else {
			//if (($this->_module=='SaleOrder' || ($this->_module=='ReturnSaleOrder' && $this->_action=='insert')) && C('sale.relation_sale_follow_up')==1) { ///del by jp 20130204 +  C('sale.relation_sale_follow_up') -> 销售后续流程
			if (($this->_module=='SaleOrder' || ($this->_module=='ReturnSaleOrder' && $this->_action=='insert')) && C('multi_storage')==2) {				///added by jp 20130204 -  C('multi_storage') -> 是否多仓库
				$storage_attr = array('product_id');
			}else {
				$storage_attr = array('warehouse_id','product_id');
			}
			
			if (C('storage_format')>=2) {
				$storage_attr[] = 'capability';
			}
			if (C('storage_format')>=3) {
				$storage_attr[] = 'dozen';
			}
			if (C('storage_color')) {
				$storage_attr[] = 'color_id';
			}
			if (C('storage_size')) {
				$storage_attr[] = 'size_id';
			}
			if (C('storage_mantissa')) {
				$storage_attr[] = 'mantissa';
			}
			$this->storage_attr = $storage_attr;
		}
	}
	
	/**
	 * 根据规格生成查询条件
	 * @param  array
	 * @param  int  1实际库存 2可销售库存
	 */
	protected function getSpecWhere($value,$type){
		$where = array();
		foreach ($this->storage_attr as $spec_field) {
			if($type==2 && $spec_field=='warehouse_id'){continue;}
			$where[] = $spec_field.'='.$value[$spec_field];
		}
		return implode(' and ',$where);
	}
	
	
	/**
	 * 合并数据中库存规格完全一致的数据
	 * @param  明细数据下标
	 * @return array
	 */
	protected function postMerge($params_key='detail'){
		if(empty($this->params[$params_key])){return false;}
		$new_params = array();
		// 定义流程数据为扣减库存的模块
		$reduce = array('SaleOrder','Delivery','Transfer');
		foreach ($this->params[$params_key] as $value){
			if(empty($value['product_id']) || ($this->_module=='Transfer' && $value['id']>0) || ($this->_module=='ReturnSaleOrder' && isset($value['is_use']) && $value['is_use']!=1)) continue;
			$key = '';
			($this->reduce===true || in_array($this->_module,$reduce)) && $value['quantity'] *=-1;
			foreach ($this->storage_attr as $field){
				if(!isset($value[$field]) && !isset($this->params[$field])){throw_json('不存在库存规格数据，无法进行库存验证！');}
				$key .= $value[$field] ? $value[$field] : $value[$field] = $this->params[$field];
			}
			if (isset($new_params[$key])) {
				$new_params[$key]['quantity'] += $value['quantity'];
			}else {
				$new_params[$key] = $value;
			}
		}
		return $new_params;
	}
	
	/**
	 * 合并数据库中的库存规格完全一致的数据
	 * @return array
	 */
	protected function dbMerge(){
		$method_name =  $this->module_name.ucwords($this->_action);
		if (method_exists($this,$method_name)) {
			$id = intval($this->params['id']);
			if ($id<=0) { return false;}
			return $this->$method_name($id);
		}else {
			throw_json('库存检查方法不存在，无法进行库存验证！');
		}
	}
	
	/**
	 * 设置最终库存需要检查的数据
	 *
	 * @param uarray$post_data 页面传递的数据
	 * @param uarray $db_data 数据库中数据
	 */
	protected function setCheckData($post_data,$db_data){
		if (empty($post_data)) {
			$this->checkData = $db_data;
		}elseif (empty($db_data)){
			$this->checkData = $post_data;
		}else {
			foreach ($db_data as $db_key => &$value){
				if(empty($value['product_id'])) continue;
				$key = '';
				foreach ($this->storage_attr as $field){
					if(!isset($value[$field]) && !isset($this->params[$field])){throw_json('不存在库存规格数据，无法进行库存验证！');}
					$key .= $value[$field] ? $value[$field] : $this->params[$field];
				}
				if (isset($post_data[$key])) {
					$value['quantity'] += $post_data[$key]['quantity'];
					unset($post_data[$key]);
					if ($value['quantity']>=0) {
						unset($db_data[$db_key]);
					}
				}
			}
			if (empty($post_data) && empty($db_data)) {
				$new_data = array();
			}elseif (empty($post_data)){
				$new_data = $db_data;
			}elseif (empty($db_data)){
				$new_data = $post_data;
			}else {
				$new_data = array_merge($db_data,$post_data);
			}
			$this->checkData = $new_data;
		}
	}
	
	/**
	 * 执行库存检查
	 *
	 * @return ubool
	 */
	protected function execCheckStorage(){
		if (empty($this->checkData)) {
			return true;
		}
		static $dd_product,$dd_color,$dd_size;
		empty($dd_product) && $dd_product = S('product');
		(C('storage_color') && empty($dd_color)) && $dd_color = S('color');
		(C('storage_size') && empty($dd_size)) && $dd_size = S('size');
		foreach ($this->checkData as $value) {
			$color_str = $size_str = '';
			C('storage_color') && $color_str = '，'.$dd_color[$value['color_id']]['color_name'];
			C('storage_size') && $size_str = '，'.$dd_size[$value['size_id']]['size_name'];
			$where = $this->getSpecWhere($value);
			$rs = M($this->tableName)->where($where)->find();
//			echo M($this->tableName)->getLastSql();
			if ($rs['quantity']+$value['quantity']<0) {
				$error[] = L('product_no').'“'.$dd_product[$value['product_id']]['product_no'].$color_str.$size_str.'”'.L('storage_no_enough');
				continue;
			}
		}
		if (!empty($error)) {
			throw_json($error);
		}
	}
	
	/**
	 * 入库库存验证开始
	 *
	 * @param  int $id 主表ID
	 * @return  array
	 */
	protected function instockDelete($id){
		$info = M('InstockDetail')->field('sum(quantity*-1) as quantity,'.implode(',',$this->storage_attr))->where('instock_id='.$id)->group(implode(',',$this->storage_attr))->select();
		return $info;
	}
	protected function instockUpdate($id){
		$info = M('InstockDetail')->field('sum(quantity*-1) as quantity,'.implode(',',$this->storage_attr))->where('instock_id='.$id)->group(implode(',',$this->storage_attr))->select();
		return $info;
	}
	protected function instockDeleteDetail($id){
		$info = M('InstockDetail')->field('quantity*-1 as quantity,'.implode(',',$this->storage_attr))->where('id='.$id)->select();
		return $info;
	}
	/**
	 * 调整库存验证开始
	 *
	 * @param  int $id 主表ID
	 * @return  array
	 */
	protected function adjustInsert($id){
		return false;
	}
	
	protected function adjustUpdate($id){
		$info = M('AdjustDetail')->field('sum(quantity*-1) as quantity,'.implode(',',$this->storage_attr))->where('adjust_id='.$id)->group(implode(',',$this->storage_attr))->select();
		return $info;
	}
	
	protected function adjustDeleteDetail($id){
		$info = M('AdjustDetail')->field('quantity*-1 as quantity,'.implode(',',$this->storage_attr))->where('id='.$id)->select();
		return $info;
	}
	
	protected function adjustDelete($id){
		$info = M('AdjustDetail')->field('sum(quantity*-1) as quantity,'.implode(',',$this->storage_attr))->where('adjust_id='.$id)->group(implode(',',$this->storage_attr))->select();
		return $info;
	}
	
	
	
	/**
	 * 销售库存验证开始
	 *
	 * @param  int $id 主表ID
	 * @return  array
	 */
	protected function saleOrderInsert($id){
		return false;
	}
	
	protected function saleOrderUpdate($id){
		$info = M('SaleOrderDetail')->field('sum(quantity) as quantity,'.implode(',',$this->storage_attr))->where('sale_order_id='.$id)->group(implode(',',$this->storage_attr))->select();
		return $info;
	}
	
	protected function saleOrderDeleteDetail($id){
		$info = M('SaleOrderDetail')->field('quantity,'.implode(',',$this->storage_attr))->where('id='.$id)->select();
		return $info;
	}
	
	/**
	 * 退货中的换货库存检查
	 */
	protected function returnSaleOrderInsert($id){
		return false;
	}
	
	protected function returnSaleOrderUpdate($id){
		$info = M('ReturnSaleOrderDetail')->field('sum(quantity*-1) as quantity,'.implode(',',$this->storage_attr))->where('return_sale_order_id='.$id.' and is_use=1')->group(implode(',',$this->storage_attr))->select();
		return $info;
	}
	
	protected function returnSaleOrderDelete($id){
		$info = M('ReturnSaleOrderDetail')->field('sum(quantity*-1) as quantity,'.implode(',',$this->storage_attr))->where('return_sale_order_id='.$id.' and is_use=1')->group(implode(',',$this->storage_attr))->select();
		return $info;
	}
	
	protected function returnSaleOrderDeleteDetail($id){
		$info = M('ReturnSaleOrderDetail')->field('quantity*-1 as quantity,'.implode(',',$this->storage_attr))->where('id='.$id)->select();
		if ($info['is_use']==1) {
			return $info;
		}
		return false;
	}
	
	
	/**
	 * 发货库存验证开始
	 *
	 * @param  int $id 主表ID
	 * @return  array
	 */
	protected function deliveryInsert($id){
		return false;
	}
	
	protected function deliveryUpdate($id){
		$info = M('DeliveryDetail')->field('sum(quantity) as quantity,'.implode(',',$this->storage_attr))->where('delivery_id='.$id)->group(implode(',',$this->storage_attr))->select();
		return $info;
	}
	
	/**
	 * 期初库存验证开始
	 *
	 * @param  int $id 主表ID
	 * @return  array
	 */
	protected function initStorageInsert($id){
		return false;
	}
	
	protected function initStorageUpdate($id){
		$info = M('InitStorageDetail')->join('init_storage on(init_storage_detail.init_storage_id=init_storage.id)')->field('sum(quantity*-1) as quantity,'.implode(',',$this->storage_attr))->where('init_storage_id='.$id)->group(implode(',',$this->storage_attr))->select();
		return $info;
	}
	
	protected function initStorageDelete($id){
		$info = M('InitStorageDetail')->join('init_storage on(init_storage_detail.init_storage_id=init_storage.id)')->field('sum(quantity*-1) as quantity,'.implode(',',$this->storage_attr))->where('init_storage_id='.$id)->group(implode(',',$this->storage_attr))->select();
		return $info;
	}
	
	protected function initStorageDeleteDetail($id){
		$info = M('InitStorageDetail')->join('init_storage on(init_storage_detail.init_storage_id=init_storage.id)')->field('quantity*-1 as quantity,'.implode(',',$this->storage_attr))->where('init_storage_detail.id='.$id)->select();
		return $info;
	}
	
	/**
	 * 调拨库存验证开始
	 *
	 * @param  int $id 主表ID
	 * @return  array
	 */
	protected function transferInsert($id){
		return false;
	}
	
	protected function transferUpdate($id){
		return false;
	}
	protected function transferDelete($id){
		$info = M('TransferDetail')->field('sum(quantity*-1) as quantity,in_warehouse_id as '.implode(',',$this->storage_attr))->where('transfer_id='.$id)->group(implode(',',$this->storage_attr))->select();
		return $info;
	}
	protected function transferDeleteDetail($id){
		$info = M('TransferDetail')->field('quantity*-1 as quantity,in_warehouse_id as '.implode(',',$this->storage_attr))->where('id='.$id)->select();
		return $info;
	}
	
	/**
	 * 添加库存的模块需要执行先进先出验证
	 *
	 * @param  int $id
	 * @param  array $post_data
	 * @return unknown
	 */
	protected function checkFiFo($id,$post_data){
		$fifo_module = array('Instock','Adjust','InitStorage','ReturnSaleOrder');
		$fifo_action = array('update','delete','deleteDetail');
		$module_id	 = array('Instock'=>'instock_id','Adjust'=>'adjust_id','InitStorage'=>'init_storage_id','ReturnSaleOrder'=>'return_sale_order_id');
		if (!in_array($this->_module,$fifo_module) || !in_array($this->_action,$fifo_action)) {
			return true;
		}
		$error = array();
		switch ($this->_action){
			case 'delete':
				$data = M($this->_module.'Detail')->where($module_id[$this->_module].'='.$id)->select();
				foreach ((array)$data as $value) {$this->checkFiFoDetail($value['id'],$error);}
				break;
			case 'deleteDetail':
				$this->checkFiFoDetail($id,$error);
				break;
			case 'update':
				// 新明细记录为增加库存时不验证
				$data = $this->resetFiFoData();
				foreach ((array)$data as $value) {$this->checkFiFoDetail($value['id'],$error,$value);}
				break;
		}
		if (!empty($error)) {
			throw_json($error);
		}
	}
	
	/**
	 * 合并数据中库存规格完全一致的数据
	 * @param  明细数据下标
	 * @return array
	 */
	protected function resetFiFoData($params_key='detail'){
		if(empty($this->params[$params_key])){return false;}
		$new_params = array();
		foreach ($this->params[$params_key]  as $key=>$value){
			if(empty($value['id'])) continue;
			if (!isset($value['warehouse_id'])) {
				$value['warehouse_id'] = $this->params['warehouse_id'];
			}
			$new_params[$key] = $value;
		}
		return $new_params;
	}
	
	/**
	 * 检查是否先进先出，已删除先进先出验证，不用该方法。
	 */
	protected function checkFiFoDetail($detail_id,&$error,$value=null){
		static $dd_product,$dd_color,$dd_size;
		$color_str = $size_str = '';
		if(empty($dd_product)) $dd_product = S('product');
		(empty($dd_color) && C('storage_color')) && $dd_color = S('color');
		(empty($dd_size) && C('storage_size')) && $dd_size = S('size');
		$module_realtion = array('Instock'=>2,'Adjust'=>4,'InitStorage'=>8,'ReturnSaleOrder'=>5);
		$relation = $module_realtion[$this->_module];
		$var = M('StockIn')->field('quantity-balance as use_quantity,product_id,color_id,size_id,balance,warehouse_id,capability,dozen,mantissa')->where('relation_type='.$relation.' and detail_id='.$detail_id)->find();
		if (empty($var)) {
			return true;
		}
		C('storage_color') && $color_str = '，'.$dd_color[$var['color_id']]['color_name'];
		C('storage_size') && $size_str = '，'.$dd_size[$var['size_id']]['size_name'];
		if ($value) {
			// 产品未做任何出库可任意修改
			if($var['use_quantity']==0) { return true;}
			// 修改规格时只要有任何出库记录修改失败
			$flag = true;
			foreach ($this->storage_attr as $field) {
				if ($var[$field]!=$value[$field] && $var['use_quantity']!=0) {
					$error[] = L('product_no').'“'.$dd_product[$var['product_id']]['product_no'].$color_str.$size_str.'”'.L('storage_error_2').'“'.$var['use_quantity'].'”，'.L('oper_error');
					$flag = false;
					break;
				}
			}
			// 只在规格一致且存在指定出库时再验证数量
			if ($flag==true && $var['use_quantity']>$value['quantity']) {
				$error[] = L('product_no').'“'.$dd_product[$var['product_id']]['product_no'].$color_str.$size_str.'”'.L('storage_error_2').'“'.$var['use_quantity'].'”，'.L('oper_error');
			}
		}else {
			if ($var['use_quantity']>0) {
				$error[] = L('product_no').'“'.$dd_product[$var['product_id']]['product_no'].$color_str.$size_str.'”'.L('storage_error_2').'“'.$var['use_quantity'].'”，'.L('oper_error');
			}
		}
	}
	
}